local Class = require('lua.lang.Class')

--- @class Lua : Class
local Lua = Class {}

Lua._VERSION = "Lua-L 1.0"
Lua.LUA_MULTRET = -1
Lua.iABC = 0
Lua.iABx = 1
Lua.iAsBx = 2
Lua.iAx = 3
Lua.SIZE_C = 9
Lua.SIZE_B = 9
Lua.SIZE_A = 8
Lua.SIZE_OP = 6
Lua.POS_OP = 0
Lua.OP_MOVE = 0
Lua.OP_LOADK = 1
Lua.OP_LOADKX = 2
Lua.OP_LOADBOOL = 3
Lua.OP_LOADNIL = 4
Lua.OP_GETUPVAL = 5
Lua.OP_GETTABUP = 6
Lua.OP_GETTABLE = 7
Lua.OP_SETTABUP = 8
Lua.OP_SETUPVAL = 9
Lua.OP_SETTABLE = 10
Lua.OP_NEWTABLE = 11
Lua.OP_SELF = 12
Lua.OP_ADD = 13
Lua.OP_SUB = 14
Lua.OP_MUL = 15
Lua.OP_DIV = 16
Lua.OP_MOD = 17
Lua.OP_POW = 18
Lua.OP_UNM = 19
Lua.OP_NOT = 20
Lua.OP_LEN = 21
Lua.OP_CONCAT = 22
Lua.OP_JMP = 23
Lua.OP_EQ = 24
Lua.OP_LT = 25
Lua.OP_LE = 26
Lua.OP_TEST = 27
Lua.OP_TESTSET = 28
Lua.OP_CALL = 29
Lua.OP_TAILCALL = 30
Lua.OP_RETURN = 31
Lua.OP_FORLOOP = 32
Lua.OP_FORPREP = 33
Lua.OP_TFORCALL = 34
Lua.OP_TFORLOOP = 35
Lua.OP_SETLIST = 36
Lua.OP_CLOSURE = 37
Lua.OP_VARARG = 38
Lua.OP_EXTRAARG = 39
Lua.OP_IDIV = 40
Lua.OP_BNOT = 41
Lua.OP_BAND = 42
Lua.OP_BOR = 43
Lua.OP_BXOR = 44
Lua.OP_SHL = 45
Lua.OP_SHR = 46
Lua.LFIELDS_PER_FLUSH = 50
Lua.MAXSRC = 80

Lua.SIZE_Bx = Lua.SIZE_C + Lua.SIZE_B
Lua.SIZE_Ax = Lua.SIZE_C + Lua.SIZE_B + Lua.SIZE_A
Lua.POS_A = Lua.POS_OP + Lua.SIZE_OP
Lua.POS_C = Lua.POS_A + Lua.SIZE_A
Lua.POS_B = Lua.POS_C + Lua.SIZE_C
Lua.POS_Bx = Lua.POS_C
Lua.POS_Ax = Lua.POS_A

Lua.MAX_OP = (1 << Lua.SIZE_OP) - 1
Lua.MAXARG_A = (1 << Lua.SIZE_A) - 1
Lua.MAXARG_B = (1 << Lua.SIZE_B) - 1
Lua.MAXARG_C = (1 << Lua.SIZE_C) - 1
Lua.MAXARG_Bx = (1 << Lua.SIZE_Bx) - 1
Lua.MAXARG_sBx = Lua.MAXARG_Bx >> 1
Lua.MAXARG_Ax = (1 << Lua.SIZE_Ax) - 1

Lua.MASK_OP = ((1 << Lua.SIZE_OP) - 1) << Lua.POS_OP
Lua.MASK_A = ((1 << Lua.SIZE_A) - 1) << Lua.POS_A
Lua.MASK_B = ((1 << Lua.SIZE_B) - 1) << Lua.POS_B
Lua.MASK_C = ((1 << Lua.SIZE_C) - 1) << Lua.POS_C
Lua.MASK_Bx = ((1 << Lua.SIZE_Bx) - 1) << Lua.POS_Bx

--- @type number
Lua.MASK_NOT_OP = ~Lua.MASK_OP
--- @type number
Lua.MASK_NOT_A = ~Lua.MASK_A
--- @type number
Lua.MASK_NOT_B = ~Lua.MASK_B
--- @type number
Lua.MASK_NOT_C = ~Lua.MASK_C
--- @type number
Lua.MASK_NOT_Bx = ~Lua.MASK_Bx

--- @param i number
--- @return number
function Lua:getOpCode(i)
	return (i >> self.POS_OP) & self.MAX_OP
end

--- @param i number
--- @return number
function Lua:getArgA(i)
	return (i >> self.POS_A) & self.MAXARG_A
end

--- @param i number
--- @return number
function Lua:getArgAx(i)
	return (i >> self.POS_A) & self.MAXARG_Ax
end

--- @param i number
--- @return number
function Lua:getArgB(i)
	return (i >> self.POS_B) & self.MAXARG_B
end

--- @param i number
--- @return number
function Lua:getArgC(i)
	return (i >> self.POS_C) & self.MAXARG_C
end

--- @param i number
--- @return number
function Lua:getArgBx(i)
	return (i >> self.POS_Bx) & self.MAXARG_Bx
end

--- @param i number
--- @return number
function Lua:getArgSbx(i)
	return ((i >> self.POS_Bx) & self.MAXARG_Bx) - self.MAXARG_sBx
end

Lua.BIT_RK = 1 << (Lua.SIZE_B - 1)

--- @param x number
--- @return boolean
function Lua:isk(x)
	return 0 ~= (x & self.BIT_RK)
end

--- @param x number
--- @return number
function Lua:indexK(x)
	return x & ~self.BIT_RK
end

Lua.MAXINDEXRK = Lua.BIT_RK - 1

--- @param x number
--- @return number
function Lua:rkAsK(x)
	return x | self.BIT_RK
end

Lua.NO_REG = Lua.MAXARG_A

Lua.NUM_OPCODES = Lua.OP_SHR + 1

Lua.OP_GT = 63
Lua.OP_GE = 62
Lua.OP_NEQ = 61
Lua.OP_AND = 60
Lua.OP_OR = 59
Lua.OpArgN = 0
Lua.OpArgU = 1
Lua.OpArgR = 2
Lua.OpArgK = 3

Lua.luaPOpModes = {
	-- T          A               B                   C             mode	   opcode
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_MOVE
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgN << 2) | Lua.iABx, -- OP_LOADK
	(0 << 7) | (1 << 6) | (Lua.OpArgN << 4) | (Lua.OpArgN << 2) | Lua.iABx, -- OP_LOADKX
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_LOADBOOL
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_LOADNIL
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_GETUPVAL
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_GETTABUP
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_GETTABLE
	(0 << 7) | (0 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SETTABUP
	(0 << 7) | (0 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_SETUPVAL
	(0 << 7) | (0 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SETTABLE
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_NEWTABLE
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SELF
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_ADD
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SUB
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_MUL
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_DIV
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_MOD
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_POW
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_UNM
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_NOT
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_LEN
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgR << 2) | Lua.iABC, -- OP_CONCAT
	(0 << 7) | (0 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iAsBx, -- OP_JMP
	(1 << 7) | (0 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_EQ
	(1 << 7) | (0 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_LT
	(1 << 7) | (0 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_LE
	(1 << 7) | (0 << 6) | (Lua.OpArgN << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_TEST
	(1 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_TESTSET
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_CALL
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_TAILCALL
	(0 << 7) | (0 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_RETURN
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iAsBx, -- OP_FORLOOP
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iAsBx, -- OP_FORPREP
	(0 << 7) | (0 << 6) | (Lua.OpArgN << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_TFORCALL
	(1 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iAsBx, -- OP_TFORLOOP
	(0 << 7) | (0 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iABC, -- OP_SETLIST
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABx, -- OP_CLOSURE
	(0 << 7) | (1 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_VARARG
	(0 << 7) | (0 << 6) | (Lua.OpArgU << 4) | (Lua.OpArgU << 2) | Lua.iAx, -- OP_EXTRAARG
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_IDIV
	(0 << 7) | (1 << 6) | (Lua.OpArgR << 4) | (Lua.OpArgN << 2) | Lua.iABC, -- OP_BNOT
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_BAND
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_BOR
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_BXOR
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SHL
	(0 << 7) | (1 << 6) | (Lua.OpArgK << 4) | (Lua.OpArgK << 2) | Lua.iABC, -- OP_SHR
}

--- @param m number
--- @return number
function Lua:getOpMode(m)
	return self.luaPOpModes[m + 1] & 3
end

--- @param m number
--- @return number
function Lua:getBMode(m)
	return self.luaPOpModes[m + 1] >> 4 & 3
end

--- @param m number
--- @return number
function Lua:getCMode(m)
	return self.luaPOpModes[m + 1] >> 2 & 3
end

--- @param m number
--- @return boolean
function Lua:testAMode(m)
	return 0 ~= self.luaPOpModes[m + 1] & (1 << 6)
end

--- @param m number
--- @return boolean
function Lua:testTMode(m)
	return 0 ~= self.luaPOpModes[m + 1] & (1 << 7)
end

--- @param source string
--- @return string
function Lua:chunkId(source)
	if source:startsWith('=') then
		return source:sub(2)
	end
	local tail = ''
	if source:startsWith('@') then
		source = source:sub(2)
	else
		source = '[string \34' .. source
		tail = '\34]'
	end
	local n = source:len() + tail:len()
	if n > self.MAXSRC then
		source = source:sub(1, self.MAXSRC - tail:len() - 4) .. '...'
	end
	return source .. tail
end

return Lua